// C++ Templates: 第13.4.2节 依赖基类
// 13.4.2 依赖基类
// 依赖基类是指依赖于模板参数的基类。与非依赖基类不同，依赖基类的具体类型在模板定义时是未知的，只有在模板实例化时才能确定。这导致了一系列特殊的名称查找规则和语法要求。
// 依赖基类示例
template <typename T>
class Derived1 : public Base<T> {  // 依赖于T
  // ...
};

template <typename T>
class Derived2 : public T {  // 直接依赖于T
  // ...
};

template <typename T>
class Derived3 : public std::vector<T> {  // 依赖于T
  // ...
};
// 依赖基类的特点
// 1.基类在实例化时确定：
template <typename Base>
class Derived : public Base
{ // Base是依赖基类
  // ...
};

// 2.名称查找规则：
// 依赖基类中的名称在模板实例化时（第二阶段）才会被查找
// 这些名称不会在模板定义时被考虑
// 需要特殊语法来访问依赖基类的成员

// 3.成员访问语法：
// 必须使用this->前缀、类名限定或using声明
// 直接使用基类成员名称会导致查找失败

// 访问依赖基类成员的方法
// 有三种主要方法可以访问依赖基类的成员：
// 1.使用this->前缀：
template <typename Base>
class Derived : public Base
{
public:
    void foo()
    {
        this->method(); // 使用this->访问Base::method
    }
};

// 2.使用基类名称限定：
template <typename Base>
class Derived : public Base
{
public:
    void foo()
    {
        Base::method(); // 使用Base::访问method
    }
};

// 3.使用using声明：
template <typename Base>
class Derived : public Base
{
public:
    using Base::method; // 将Base::method引入当前作用域

    void foo()
    {
        method(); // 现在可以直接调用
    }
};

// 为什么需要特殊语法
// 这种特殊语法的需求源于C++的两阶段名称查找机制：
// 1.在模板定义时，编译器不知道依赖基类中有哪些成员
// 2.如果直接使用成员名称，编译器会在当前作用域和非依赖基类中查找，但不会考虑依赖基类
// 3.使用this->或类名限定告诉编译器这是一个依赖名称，应该在第二阶段查找
// 一个简单的CRTP例子
template <typename Derived>
class Base
{
public:
    void interface()
    {
        static_cast<Derived *>(this)->implementation();
    }

    // 默认实现
    void implementation()
    {
        std::cout << "Base implementation" << std::endl;
    }
};

template <typename T>
class SpecialProcessor : public Base<SpecialProcessor<T>>
{
public:
    void implementation()
    {
        std::cout << "SpecialProcessor implementation for " << typeid(T).name() << std::endl;
    }

    void process(const T &data)
    {
        // 调用从Base继承的方法
        this->interface(); // 需要this->前缀
    }
};
